package com.xiaoyu.lanling.util;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import com.zxy.tiny.Tiny;
import com.zxy.tiny.common.FileResult;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import in.srain.cube.util.LocalDisplay;
import io.reactivex.Single;

public class ImageFileCompressUtils {

    private static final int QUALITY = 75;
    private static final int AVATAR_WIDTH = 640;
    private static final int AVATAR_HEIGHT = 640;

    public static Single<String> compressAsFile(String filePath) {
        return Single.create(e -> {
            final Tiny.FileCompressOptions fileCompressOptions = new Tiny.FileCompressOptions();
            fileCompressOptions.quality = QUALITY;
            Tiny.getInstance().source(filePath).asFile().withOptions(fileCompressOptions).compress((isSuccess, outfile, t) -> {
                if (isSuccess) {
                    e.onSuccess(outfile);
                } else {
                    e.onError(checkThrowable(t));
                }
            });
        });
    }

    public static Single<String> compressAsFile(Bitmap bitmap) {
        return Single.create(e -> {
            final Tiny.FileCompressOptions fileCompressOptions = new Tiny.FileCompressOptions();
            fileCompressOptions.quality = QUALITY;
            Tiny.getInstance().source(bitmap).asFile().withOptions(fileCompressOptions).compress((isSuccess, outfile, t) -> {
                if (isSuccess) {
                    e.onSuccess(outfile);
                } else {
                    e.onError(checkThrowable(t));
                }
            });
        });
    }

    public static String compressAsFileSync(Bitmap bitmap) {
        final Tiny.FileCompressOptions fileCompressOptions = new Tiny.FileCompressOptions();
        fileCompressOptions.quality = QUALITY;
        FileResult fileResult = Tiny.getInstance().source(bitmap).asFile().withOptions(fileCompressOptions).compressSync();
        return fileResult.outfile;
    }

    public static Single<String[]> compressBatchAsFile(String[] filePaths) {
        return Single.create(e -> {
            final Tiny.FileCompressOptions fileCompressOptions = new Tiny.FileCompressOptions();
            fileCompressOptions.quality = QUALITY;
            Tiny.getInstance().source(filePaths).batchAsFile().withOptions(fileCompressOptions).batchCompress((isSuccess, outfile, t) -> {
                if (isSuccess) {
                    e.onSuccess(outfile);
                } else {
                    e.onError(checkThrowable(t));
                }
            });
        });
    }

    public static Single<String[]> compressBatchAsFile(List<String> filePaths) {
        return compressBatchAsFile(filePaths.toArray(new String[0]));
    }

    public static Single<String> compressAsFileForAvatar(String filePath) {
        return compressAsFile(filePath, AVATAR_WIDTH, AVATAR_HEIGHT);
    }

    public static Single<String> compressAsFileForBackground(String filePath) {
        return compressAsFile(filePath, LocalDisplay.SCREEN_WIDTH_PIXELS, LocalDisplay.SCREEN_HEIGHT_PIXELS);
    }

    public static Single<String> compressAsFile(String filePath, int width, int height) {
        return Single.create(e -> {
            final Tiny.BitmapCompressOptions bitmapCompressOptions = new Tiny.BatchFileCompressOptions();
            bitmapCompressOptions.width = width;
            bitmapCompressOptions.height = height;
            Tiny.getInstance().source(filePath).asBitmap().withOptions(bitmapCompressOptions).compress((isSuccess, bitmap, t) -> {
                if (isSuccess) {
                    compressAsFile(bitmap).subscribe(e::onSuccess, e::onError);
                } else {
                    e.onError(checkThrowable(t));
                }
            });
        });
    }

    public static Single<File> createFileForBitmap(Bitmap bitmap, File file) {
        return Single.create(emitter -> {
            try {
                if (bitmap == null || file == null) {
                    emitter.onError(new NullPointerException("data null"));
                    return;
                }
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bufferedOutputStream);
                bufferedOutputStream.flush();
                bufferedOutputStream.close();
                emitter.onSuccess(file);
            } catch (IOException e) {
                emitter.onError(e);
            }
        });
    }

    public static Single<File> createFileForByte(final byte[] data, File file) {
        return Single.create(emitter -> {
            try {
                if (data == null || file == null) {
                    emitter.onError(new NullPointerException("data null"));
                    return;
                }
                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));
                bufferedOutputStream.write(data);
                bufferedOutputStream.flush();
                bufferedOutputStream.close();
                emitter.onSuccess(file);
            } catch (IOException e) {
                emitter.onError(e);
            }
        });
    }

    public static Single<Bitmap> createBitmapForByte(final byte[] data) {
        return Single.create(emitter -> {
            if (data == null) {
                emitter.onError(new NullPointerException("data null"));
                return;
            }
            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            emitter.onSuccess(bitmap);
        });
    }

    private static Throwable checkThrowable(Throwable throwable) {
        if (throwable == null) {
            return new Throwable("error");
        }
        return throwable;
    }
}
